// @file      TextParser.groovy
// @author    Mac Radigan
// @purpose   parse text files, i.e. CSV, etc

package ycoa.text

def class TextParser {

  private File file
  //private String text = null
  private String fieldSeparator = ","
  private String recordSeparator = "\r"
  private String escapeSeparator = "\""
  private ArrayList<ArrayList<String>> recordSet = new ArrayList()

  public TextParser(String filename) throws Exception {
    this.file = new File(filename)
    parse()
  }

  public TextParser(String filename, 
                    String fieldSeparator, 
                    String recordSeparator,
                    String escapeSeparator) throws Exception {
    this.file = new File(filename)
    this.fieldSeparator = fieldSeparator
    this.recordSeparator = recordSeparator
    this.escapeSeparator = escapeSeparator
    parse()
  }

  public ArrayList<ArrayList<String>> readAll() {
    return recordSet
  }

  public void debugPrint() {
    def recordCounter = 0
    def fieldCounter = 0
    for(ArrayList<String> record : recordSet) {
      recordCounter++
      println "${recordCounter}:"
      for(String field : record) {
        fieldCounter++
        println "  ${fieldCounter} ==>  ${field}"
      }
    }
  }

  private void parse() {
    try {
      def text = file.text
      def stateRecord = 0
      def stateField = 1
      def stateEscape = 2
      def buffer = ""
      def state = 0
      def record = new ArrayList()
      for(int cursor=0; cursor<text.length(); cursor++) {
         //println text.charAt(cursor)
         switch(text.charAt(cursor)) {
           case recordSeparator:
             //println "record sep"
             switch(state) {
               case stateEscape:
                 buffer += text.charAt(cursor)
                 break
               default:
                 if(text.charAt(cursor+1)=='\r') cursor++ // consume \r\n
                 if(text.charAt(cursor+1)=='\n') cursor++ // consume \r\n
                 record.add(buffer)
                 recordSet.add(record)
                 record = new ArrayList()
                 buffer = ""
                 break
             }
             break
           case fieldSeparator:
             //println "field sep"
             switch(state) {
               case stateEscape:
                 buffer += text.charAt(cursor)
                 break
               default:
                 record.add(buffer)
                 buffer = ""
                 break
             }
             break
           case escapeSeparator:
             //println "escape sep"
             switch(state) {
               case stateEscape:
                 state = stateField
                 break
               default:
                 state = stateEscape
                 break
             }
             break
           default:
             buffer += text.charAt(cursor)
             break
         }
      }
    } catch(e) {
      e.printStackTrace()
      throw new Exception(e)
    }
  }


} // end of class Renderer
